package com.yj.timecapsule.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.yj.timecapsule.common.constant.JwtKey;
import com.yj.timecapsule.common.context.LoginUserContext;
import com.yj.timecapsule.common.enums.ErrorCode;
import com.yj.timecapsule.common.enums.FriendRequestStatusEnum;
import com.yj.timecapsule.common.error.BusinessException;
import com.yj.timecapsule.common.utils.JwtUtil;
import com.yj.timecapsule.common.utils.PhoneNumberValidator;
import com.yj.timecapsule.common.utils.RedisUtil;
import com.yj.timecapsule.entity.diaries.Diaries;
import com.yj.timecapsule.entity.diaries.vo.DiariesVo;
import com.yj.timecapsule.entity.likes.Likes;
import com.yj.timecapsule.entity.user.FriendRequest;
import com.yj.timecapsule.entity.user.Friends;
import com.yj.timecapsule.entity.user.Users;
import com.yj.timecapsule.entity.user.dto.UserLoginDto;
import com.yj.timecapsule.entity.user.vo.*;
import com.yj.timecapsule.mapper.*;
import com.yj.timecapsule.service.diaries.DiariesService;
import com.yj.timecapsule.service.likes.LikesService;
import com.yj.timecapsule.service.sms.SmsService;
import com.yj.timecapsule.service.user.UserService;
import io.netty.util.concurrent.Promise;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    private static final Object LOCK = new Object();
    private static boolean hasNewRequest = false;
    private static final long timeout = 10000;
    @Resource
    private UsersMapper usersMapper;
    @Resource
    private SmsService smsService;
    @Resource
    private FriendsMapper friendsMapper;
    @Resource
    private FriendRequestMapper friendRequestMapper;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private LikesMapper likesMapper;
    @Resource
    private DiariesService diariesService;

    @Override
    public Map<Long, MessageUserVo> getUserInfoMap(Long... userIds) {
        // 查询用户信息
        List<Users> users = usersMapper.findByIdIn(Arrays.asList(userIds));

        // 创建用户信息 Map
        Map<Long, MessageUserVo> userMap = new HashMap<>();
        for (Users user : users) {
            MessageUserVo userVo = new MessageUserVo();
            userVo.setId(user.getId());
            userVo.setUsername(user.getUsername());
            userVo.setAvatar(user.getAvatar());
            userMap.put(user.getId(), userVo);
        }

        return userMap;
    }

    @Override
    public UserLoginVo login(UserLoginDto dto) {
        PhoneNumberValidator.valid(dto.getPhone());
        smsService.verifyCode(dto.getPhone(), dto.getCode());
        Date now = new Date();
        // 登录成功
        Users user = usersMapper.selectByPhone(dto.getPhone());
        if (user == null) {
            // 新用户 自动注册
            user = new Users();
            user.setUsername(dto.getPhone());
            user.setCreatedAt(now);
            user.setPhone(dto.getPhone());
            user.setPassword("123456");
            usersMapper.insertSelective(user);
        }
        UserLoginVo vo = new UserLoginVo();
        BeanUtils.copyProperties(user, vo);
        Map<String, Object> map = new HashMap<>();
        map.put("userId", user.getId());
        String token = JwtUtil.create(vo.getId().toString(), JwtKey.SECRET_KEY, map);
        vo.setToken(token);
        redisUtil.set(token,token,3, TimeUnit.HOURS);
        return vo;
    }

    @Override
    public Users getInfo(Long userId) {
        if (userId != null) {
            return usersMapper.selectByPrimaryKey(userId);
        } else {
            return null;
        }
    }

    @Override
    public void setBackgroundImage(String images) {
        Long id = LoginUserContext.getId();
        Users users = new Users();
        users.setId(id);
        users.setDiariesImage(images);
        usersMapper.updateByPrimaryKeySelective(users);
    }

    @Override
    public void setAvatar(String avatar) {
        Long id = LoginUserContext.getId();
        Users users = new Users();
        users.setId(id);
        users.setAvatar(avatar);
        usersMapper.updateByPrimaryKeySelective(users);
    }

    @Override
    public List<FriendsVo> getFriendList() {
        Long currentUserId = LoginUserContext.getId();
        List<Friends> friendsList = friendsMapper.selectByUserId(currentUserId);

        if (CollectionUtil.isEmpty(friendsList)) {
            return new ArrayList<>();
        }
        // 获取出所有的friendsId
        List<Long> friendsIdList = friendsList.stream().map(Friends::getFriendId).collect(Collectors.toList());

        List<Users> usersList = usersMapper.selectByIds(friendsIdList);
        if (CollectionUtil.isEmpty(usersList)) {
            return new ArrayList<>();
        }
        List<FriendsVo> result = new ArrayList<>();
        usersList.forEach(users -> {
            FriendsVo vo = new FriendsVo();
            vo.setUserId(users.getId());
            vo.setAvatar(users.getAvatar());
            vo.setUsername(users.getUsername());
            result.add(vo);
        });

        return result;
    }

    @Override
    public Map<String, Object> getFriendRequest() {
        synchronized (LOCK) {
            List<FriendRequest> friendRequestList = friendRequestMapper.selectByReceiverIdWithPending(LoginUserContext.getId());
            if (friendRequestList.isEmpty()) {
                try {
                    LOCK.wait(timeout);
                    if (!hasNewRequest) {
                        log.info("10 seconds have passed... return a empty collection...");
                        return createEmptyResult();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return createEmptyResult();
                }
            }
            List<FriendRequest> latestFriendRequestList = friendRequestMapper.selectByReceiverIdWithPending(LoginUserContext.getId());
            hasNewRequest = false;
            Map<String, Object> result = new HashMap<>();
            result.put("total", latestFriendRequestList.size());
            List<FriendsRequestVo> voList = new ArrayList<>();

            List<Long> ids = latestFriendRequestList.stream().map(FriendRequest::getSenderId).toList();
            List<Users> usersList = usersMapper.selectByIds(ids);
            latestFriendRequestList.forEach(friendRequest -> {
                FriendsRequestVo friendsRequestVo = new FriendsRequestVo();
                Long senderId = friendRequest.getSenderId();
                usersList.forEach(u -> {
                    if (u.getId().equals(senderId)) {
                        friendsRequestVo.setSenderId(u.getId());
                        friendsRequestVo.setUsername(u.getUsername());
                        friendsRequestVo.setAvatar(u.getAvatar());
                    }
                });
                voList.add(friendsRequestVo);
            });
            result.put("list", voList);
            return result;
        }

    }

    /**
     * 当有新的好友请求时调用此方法
     */
    public void onNewFriendRequest() {
        synchronized (LOCK) {
            hasNewRequest = true;
            LOCK.notifyAll(); // 唤醒所有等待的线程
        }
    }

    private Map<String, Object> createEmptyResult() {
        Map<String, Object> result = new HashMap<>();
        result.put("total", 0);
        result.put("list", new ArrayList<>());
        return result;
    }

    @Override
    public void requestFriend(Long receiverId) {
        Long senderId = LoginUserContext.getId();
        if (senderId.equals(receiverId)) {
            throw new BusinessException(ErrorCode.SELF_FRIEND_REQUEST);
        }
        FriendRequest friendRequest = new FriendRequest();
        friendRequest.setSenderId(senderId);
        friendRequest.setReceiverId(receiverId);
        friendRequest.setStatus(FriendRequestStatusEnum.getPendingStr());
        friendRequestMapper.insertSelective(friendRequest);
        // 唤醒线程
        this.onNewFriendRequest();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void agreeFriendRequest(Long senderId) {
        Long receiverId = LoginUserContext.getId();
        FriendRequest friendRequest = new FriendRequest();
        friendRequest.setReceiverId(receiverId);
        friendRequest.setSenderId(senderId);
        friendRequest.setStatus(FriendRequestStatusEnum.getAcceptedStr());
        friendRequestMapper.updateBySenderIdAndReceiverId(friendRequest);
        Friends friends = new Friends();
        friends.setUserId(senderId);
        friends.setFriendId(receiverId);
        friendsMapper.insertSelective(friends);
        Friends friends2 = new Friends();
        friends2.setUserId(receiverId);
        friends2.setFriendId(senderId);
        friendsMapper.insertSelective(friends2);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void delFriend(Long friendId) {
        if (friendId == null) {
            throw new BusinessException(ErrorCode.FAIL);
        }
        Long currentUserId = LoginUserContext.getId();
        friendsMapper.deleteByUserIdAndFriendId(currentUserId, friendId);
        friendsMapper.deleteByUserIdAndFriendId(friendId, currentUserId);
    }

    @Override
    public UserVo getUserDetail() {
        Long userId = LoginUserContext.getId();
        Users userDB = usersMapper.selectByPrimaryKey(userId);
        List<Likes> likesList = likesMapper.selectByUserId(userId);
        // 获取日记id
        List<Long> diariesIdList = likesList.stream().map(Likes::getDiaryId).toList();
        List<DiariesVo> diariesVoList = diariesService.selectByIds(diariesIdList);
        List<Diaries> diaries = diariesService.selectByUserId(userId);
        // 获取所有id
        List<Long> publishIdList = diaries.stream().map(Diaries::getId).toList();
        List<DiariesVo> publishVos = diariesService.selectByIds(publishIdList);
        return UserVo.builder()
                .id(userDB.getId())
                .username(userDB.getUsername())
                .avatar(userDB.getAvatar())
                .createdAt(userDB.getCreatedAt())
                .phone(userDB.getPhone())
                .likesCount((long) likesList.size())
                .friendsCount((long) friendsMapper.selectByUserId(userId).size())
                .likesDiariesVoList(diariesVoList)
                .publishDiariesList(publishVos)
                .publishCount((long) publishVos.size())
                .build();
    }

    @Override
    public List<UserSearchVO> search(String keyWord, String phone) {
        if (phone != null) {
            Users users = usersMapper.selectByPhone(phone);
            if (users == null) {
                throw new BusinessException(ErrorCode.USER_NOT_FOUND);
            }
            UserSearchVO build = UserSearchVO.builder().avatar(users.getAvatar()).username(users.getUsername()).id(users.getId()).build();
            ArrayList<UserSearchVO> result = new ArrayList<>();
            result.add(build);
            return result;
        }

        // TODO 后续引入es来做搜索查询
        if (StringUtils.isBlank(keyWord)) {
            return new ArrayList<>();
        }
        Long currentUserId = LoginUserContext.getId();
        List<Friends> friendsList = friendsMapper.selectByFriendsId(currentUserId);
        List<Long> userIds = friendsList.stream().map(Friends::getUserId).toList();
        if (CollectionUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        List<Users> usersList = usersMapper.selectByIdsAndKeyWord(userIds, keyWord);
        List<UserSearchVO> result = BeanUtil.copyToList(usersList, UserSearchVO.class);
        if (CollectionUtil.isEmpty(result)) {
            return new ArrayList<>();
        }
        return result;
    }

    @Override
    public void rejectedFriendRequest(Long senderId) {
        Long receiverId = LoginUserContext.getId();
        FriendRequest friendRequest = new FriendRequest();
        friendRequest.setStatus(FriendRequestStatusEnum.getRejectedStr());
        friendRequest.setReceiverId(receiverId);
        friendRequest.setSenderId(senderId);
        friendRequestMapper.updateBySenderIdAndReceiverId(friendRequest);
    }

}
